import json
import logging
from langchain.chat_models import init_chat_model
from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from exception.custom_exception import CustomErrorThrowException
from tool.demo_tool import get_tool_data, get_schema_statements, database_tool, weather_search

chat_history=[

]

function_name_map={
    "weather_search": weather_search,
    "database_tool": database_tool,
    "get_schema_statements": get_schema_statements
}
async def call_tool_by_name(tool_name:str,tool_input:dict):
    func=function_name_map.get(tool_name)
    return await func(**tool_input)

async def chat_exec(user_input:str):
    model=init_chat_model(
        model="deepseek-v3",
        model_provider="openai",
        api_key="",
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
        temperature=0.5,
        max_tokens=800
    )

    system_prompt="""
    
            C - 上下文（Context）
        你是一个具有推理和问题分解能力的大语言模型。你可以在接收到一个问题后，先进行思考，然后根据问题的需要决定是否要调用某个工具。
        你不会直接调用工具，而是给出要调用的工具名称及其参数，由系统/用户帮你执行。执行结果将由外部系统再提供给你，供你继续推理下一步。
        
        🎯 O - 目标（Objective）
        你的目标是通过逐步推理和工具辅助，最终回答用户的问题。你需要：
        明确每一步的思考（thought）
        如果需要工具：提供工具名称（tool）和参数（input）
        如果不需要工具：说明你可以直接得出结论
        等待工具执行结果后，继续推理，直到给出最终结果（final_answer）
        
        ✍️ S - 风格（Style）
        使用结构化 JSON 表达每一步，格式包括：
        thought：你当前的思考
        action：若需要工具调用，包含 tool 和 input 字段；若无需工具，为 null
        不包含 observation（因为你还没拿到）
        
        🎙 T - 语气（Tone）
        语气理性、清晰、有条理，如助手或分析员，适合执行任务型对话。
        
        👥 A - 受众（Audience）
        直接读者：大语言模型，用于分步骤回答复杂问题
        中间执行者：系统或人类操作员，负责执行 action 并把结果返回给模型
        
        📦 R - 响应格式（Response Format）
        {{
          "question": "string，用户提出的问题",
          "step": {{
            "thought": "string，这一步你是如何思考的",
            "action": {{
              "tool": "string，需要调用的工具名称",
              "input": {{
                "key1": "value1"
              }}
            }}
          }}
        }}
        如果不需要工具调用，格式如下：其中结论是你当前的思考结果
        {{
          "question": "string，用户提出的问题",
          "step": {{
            "thought": "结论",
            "action": null
          }}
        }}
        
        注意：
        1.输出的 JSON 必须严格遵循上述格式，确保每个字段都存在且类型正确。不要带有markdown格式包含JSON数据或其他非 JSON 内容。
        2.特别是```json 数据 ``` 绝对不能出现用于包裹 JSON 数据的标记。
        3.绝对不要使用markdown格式数据输出
        你能够调用的工具信息如下:
        {tool_names}
    """

    question=f"我的问题是{user_input}"

    for i in range (10):

        prompt_template=ChatPromptTemplate.from_messages(
            [
                ("system",system_prompt),
                MessagesPlaceholder("chat_history"),
                ("human","{question}")
            ]
        )

        messages=prompt_template.invoke(
            {
                "question":question,
                "chat_history":chat_history,
                "tool_names": await get_tool_data()
            }
        )
        chat_history.append(HumanMessage(content=question))
        response=model.invoke(input=messages)
        logging.info(f"本轮的思考内容结果{response.content}")
        chat_history.append(AIMessage(content=response.content))
        current_result=json.loads(response.content)
        current_step=current_result.get("step",None)
        if current_step is None:
            logging.error("没有获取到当前步骤")
            raise CustomErrorThrowException(status_code=604,message="没有获取到当前步骤,请检查模型的响应内容")

        current_action=current_step.get("action",None)
        if current_action is None:
            result=current_step.get("thought","")
            logging.info(f"不需要调用工具，模型认为可以直接返回结果\n{result}")
            return result

        current_tool_name=current_action.get("tool",None)
        if current_tool_name is None:
            logging.error("当前思考需要调用工具，但是没有获取到工具名称，请检查工具名称")
            raise CustomErrorThrowException(status_code=604,message="当前思考需要调用工具，但是没有获取到工具名称，请检查工具名称")

        current_tool_input=current_action.get("input",None)
        if current_tool_input is None:
            logging.error("当前思考需要调用工具，但是没有获取到工具参数，请检查工具参数")
            raise CustomErrorThrowException(status_code=604,message="当前思考需要调用工具，但是没有获取到工具参数，请检查工具参数")

        logging.info(f"进入到工具调用环节，当前需要调用的工具名称为{current_tool_name},参数为{current_tool_input}")
        #调用工具
        tool_result=await call_tool_by_name(current_tool_name,current_tool_input)
        question=f"这是上一步工具的执行结果{tool_result},请继续思考下一步，我的问题是{user_input}"














